package org.web.accesscontrollist.server.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.web.accesscontrollist.sdk.dto.menu.MenuItem;
import org.web.accesscontrollist.server.domain.AclResourceDetailDO;
import org.web.accesscontrollist.server.domain.AclResourceUserBindingDO;
import org.web.accesscontrollist.server.domain.query.QueryAclResourceDetail;
import org.web.accesscontrollist.server.domain.query.QueryAclResourceUserBinding;
import org.web.accesscontrollist.server.service.AclResourceDetailService;
import org.web.accesscontrollist.server.service.AclResourceUserBindingService;
import org.web.base.domain.view.ViewResultDTO;

import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotEmpty;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Controller
@RequestMapping("/accountMenu")
public class AccountMenuController {

    private static final String MENU = "menu";
    private static final Set<String> SPECIFIED_ATTRIBUTE_RESOURCE_DETAIL_ID_SET  = new HashSet<>(Collections.singletonList("acl_resource_detail_id"));
    private static final Set<String> COLUMN_SET = new HashSet<>(Arrays.asList( "acl_resource_detail_id",  "business_line", "type_name", "detail_name", "detail_status", "detail_extends_value", "detail_comment", "resource_level", "first_level", "second_level", "third_level", "fourth_level", "fifth_level", "is_allow_show", "sort_num"));

    @Resource
    private AclResourceDetailService aclResourceDetailService;

    @Resource
    private AclResourceUserBindingService aclResourceUserBindingService;

    // **缓存 menuDataMap，减少 DB 访问**
    private final Map<String, AclResourceDetailDO> menuDataCache = new ConcurrentHashMap<>();

    /***
     * 指定某一个用户，在某一个业务线下，获取用户菜单列表。
     * @param userNum 不允许为空， 用户编号，即用户唯一标识。
     * @param businessLine 不允许为空， 业务线名称。
     * @return ViewResultDTO
     */
    @ResponseBody
    @RequestMapping("selectAccountMenuList")
    public ViewResultDTO<List<MenuItem>> selectAccountMenuList(@NotEmpty String userNum, @NotEmpty String businessLine) {

        String typeName = MENU;
        ViewResultDTO<List<MenuItem>> result = new ViewResultDTO<>();

        try {
            // 获取所有菜单数据（优先使用缓存）
            Map<String, AclResourceDetailDO> menuDataMap = getMenuDataMap(businessLine, typeName);

            // 获取用户授权的菜单 ID 集合 O(M)
            Set<Integer> authorizedMenuIds = getAuthorizedMenuIds(userNum, businessLine, typeName);

            // 构建完整菜单树 O(N log N)
            List<MenuItem> menuItemList = buildMenuTree(menuDataMap, authorizedMenuIds);

            result.setResult(true);
            result.setData(menuItemList);
        } catch (Exception e) {
            result.setResult(false);
            result.setMsg("获取菜单失败: " + e.getMessage());
        }

        return result;
    }

    /**
     * 获取菜单数据 Map（缓存）
     */
    private Map<String, AclResourceDetailDO> getMenuDataMap(String businessLine, String typeName) {
        // **缓存已存在直接返回**
//        if (!menuDataCache.isEmpty()) {
//            return menuDataCache;
//        }

        // **缓存未命中，查询数据库**
        QueryAclResourceDetail query = new QueryAclResourceDetail();
        query.setBusinessLine(businessLine);
        query.setTypeName(typeName);
        query.setAllRecords();
        query.setSpecifiedAttributeSet(COLUMN_SET);
        List<AclResourceDetailDO> allMenus = aclResourceDetailService.selectAclResourceDetailList(query);

        // **缓存 menuDataMap**
        menuDataCache.putAll(
                allMenus.stream().collect(Collectors.toMap(AclResourceDetailDO::getDetailName, menu -> menu))
        );

        return menuDataCache;
    }

    /**
     * 获取授权的菜单 ID 集合 O(M)
     */
    private Set<Integer> getAuthorizedMenuIds(String userNum, String businessLine, String typeName) {
        QueryAclResourceUserBinding query = new QueryAclResourceUserBinding();
        query.setUserNum(userNum);
        query.setBusinessLine(businessLine);
        query.setTypeName(typeName);
        query.setBindingStatus("ON");
        query.setSpecifiedAttributeSet(SPECIFIED_ATTRIBUTE_RESOURCE_DETAIL_ID_SET);
        query.setAllRecords();

        List<AclResourceUserBindingDO> bindings =
                aclResourceUserBindingService.selectAclResourceUserBindingList(query);

        return bindings.stream()
                .map(AclResourceUserBindingDO::getAclResourceDetailId)
                .collect(Collectors.toSet());
    }

    /**
     * 构建完整菜单树 O(N log N)
     */
    private List<MenuItem> buildMenuTree(Map<String, AclResourceDetailDO> menuDataMap, Set<Integer> authorizedMenuIds) {
        // 预处理菜单数据
        Map<String, MenuItem> menuMap = new LinkedHashMap<>();

        // 遍历授权菜单，O(M)
        for (AclResourceDetailDO menu : menuDataMap.values()) {
            if (authorizedMenuIds.contains(menu.getAclResourceDetailId())) {
                // 添加当前菜单
                MenuItem item = convertToMenuItem(menu);
                menuMap.put(item.getIndex(), item);

                // 迭代补全其父级
                addParentMenus(menu.getDetailName(), menuDataMap, menuMap);
            }
        }

        // 构建树形结构 O(N)
        List<MenuItem> rootMenus = new ArrayList<>();
        for (MenuItem item : menuMap.values()) {
            String parentIndex = getParentKey(item.getIndex());
            if (parentIndex == null || !menuMap.containsKey(parentIndex)) {
                rootMenus.add(item);
            } else {
                menuMap.get(parentIndex).addChild(item);
            }
        }

        // 对根菜单排序 O(N log N)
        rootMenus.sort(Comparator.comparing(MenuItem::getSortNum));
        return rootMenus;
    }

    /**
     * 迭代方式添加父级菜单 O(P*M)
     */
    private void addParentMenus(String index, Map<String, AclResourceDetailDO> menuDataMap, Map<String, MenuItem> menuMap) {
        while (true) {
            String parentIndex = getParentKey(index);
            if (parentIndex == null || menuMap.containsKey(parentIndex) || !menuDataMap.containsKey(parentIndex)) {
                return;
            }
            MenuItem parentItem = convertToMenuItem(menuDataMap.get(parentIndex));
            menuMap.put(parentIndex, parentItem);
            index = parentIndex;
        }
    }

    /**
     * 获取父级菜单索引 O(1)
     */
    private String getParentKey(String index) {
        int lastSlash = index.lastIndexOf("/");
        return (lastSlash <= 0) ? null : index.substring(0, lastSlash);
    }

    /**
     * 转换菜单 DO 为 MenuItem
     */
    private MenuItem convertToMenuItem(AclResourceDetailDO menu) {
        MenuItem item = new MenuItem();
        item.setIndex(menu.getDetailName());
        item.setLabel(menu.getDetailComment());
        item.setIcon(extractIcon(menu.getDetailExtendsValue()));
        item.setLevel(menu.getResourceLevel());
        item.setSortNum(menu.getSortNum());
        return item;
    }

    /**
     * 从扩展字段提取图标
     */
    private String extractIcon(String extendsValue) {
        return (extendsValue != null && extendsValue.startsWith("icon:")) ? extendsValue.substring(5) : "";
    }
}
